package cn.backflow.admin.common.treeable;

import java.util.*;

/**
 * 树形对象通用接口, 工具类
 *
 * @author backflow
 *         2014年10月16日 上午10:02:51
 */
public interface Treeable {

    String getName();

    Comparable getId();

    Comparable getParent();

    List<Treeable> getChildren();

    Treenode asTreenode();

    static List<Treeable> tree(Collection<? extends Treeable> list) {
        if (list == null || list.isEmpty()) return Collections.emptyList();
        Map<Comparable, Treeable> map = new LinkedHashMap<>(list.size());
        for (Treeable t : list) {
            map.put(t.getId(), t);
        }
        return tree(map);
    }

    static List<Treeable> tree(Map<? extends Comparable, ? extends Treeable> map) {
        return tree(map, null);
    }

    /**
     * 将数据封装成树形结构，无限级深，只需遍历一次
     */
    static List<Treeable> tree(Map<? extends Comparable, ? extends Treeable> map, Comparable root) {
        if (map == null || map.isEmpty())
            return Collections.emptyList();
        List<Treeable> tree = new ArrayList<>(map.size());
        for (Treeable v : map.values()) {
            Comparable pid = v.getParent();
            Treeable parent = map.get(pid);
            if (pid == root/* || parent == null*/)
                tree.add(v);
            else if (parent != null) {
                parent.getChildren().add(v);
            }
        }
        return tree;
    }

    /**
     * 将数据封装成 jstree.js 需要的 树形结构
     */
    static List<Treenode> jstree(
            Collection<? extends Treeable> nodes,
            Collection<? extends Comparable> selected,
            Collection<? extends Comparable> unselectable) {

        if (nodes.isEmpty())
            return Collections.emptyList();

        int size = nodes.size();
        Map<Comparable, Treenode> map = new HashMap<>(size);
        for (Treeable n : nodes) {
            Treenode node = n.asTreenode();
            if (selected != null && selected.contains(node.id))
                node.state.put("selected", true);
            else if (unselectable != null && unselectable.contains(node.id))
                node.state.put("disabled", true);
            map.put(node.id, node);
        }
        List<Treenode> tree = new ArrayList<>(size);
        for (Treenode n : map.values()) {
            Comparable pid = n.pid;
            Treenode parent = map.get(pid);
            if (pid == null || parent == null) { // 根节点
                tree.add(n);
            } else {
                parent.children.add(n);
            }
        }
        return tree;
    }

    /**
     * 构造 jquery.treetable.js 需要的数据结构
     * 查找指定元素的所有子元素并添加到其之后
     *
     * @param list 包含所有节点的列表
     * @param pid  父元素ID
     * @param tree 排序好的权限列表
     */
    static List<Treeable> sort(Collection<? extends Treeable> list, Comparable pid, List<Treeable> tree) {
        if (tree.isEmpty()) {
            for (Iterator<? extends Treeable> iterator = list.iterator(); iterator.hasNext(); ) {
                Treeable t = iterator.next();
                if (t.getId().equals(pid)) {
                    tree.add(t);
                    iterator.remove();
                }
            }
        }
        for (Treeable t : list) {
            if (pid == null) {
                if (t.getParent() != null) {
                    continue;
                }
            } else {
                if (!pid.equals(t.getParent()) || tree.contains(t)) {
                    continue;
                }
            }
            // iterator.remove();
            tree.add(t);
            sort(list, t.getId(), tree);
        }
        return tree;
    }
}